#include "cfgparser_storage_path.h"
#include <stdexcept>
#include <cstring>
#include <filesystem>
#include <cstdlib>
#include <string>
#include <vector>
#include <limits.h>

#ifdef CFGPARSER_PLATFORM_WINDOWS
#include <windows.h>
#include <shlobj.h>
#include <filesystem>
#else
#include <unistd.h>
#include <pwd.h>
#include <sys/types.h>
#ifdef CFGPARSER_PLATFORM_MACOS
#include <mach-o/dyld.h>
#endif
#endif

namespace cfgparser
{

    namespace
    {
        // 内部辅助函数：展开路径
        std::string expandPath(const std::string &path)
        {
#ifdef CFGPARSER_PLATFORM_WINDOWS
            char expanded[1024];
            DWORD result = ExpandEnvironmentStringsA(path.c_str(), expanded, sizeof(expanded));
            if (result > 0 && result <= sizeof(expanded))
            {
                return std::string(expanded);
            }
            return path;
#else
            if (path.empty())
                return path;

            if (path[0] == '~')
            {
                const char *home = std::getenv("HOME");
                if (!home)
                {
                    struct passwd *pw = getpwuid(getuid());
                    if (pw)
                    {
                        home = pw->pw_dir;
                    }
                }
                if (home)
                {
                    return std::string(home) + path.substr(1);
                }
            }
            return path;
#endif
        }
    }

    // 获取系统默认配置目录路径
    std::string get_default_config_path(const std::string &app_name)
    {
        if (app_name.empty())
        {
            throw std::invalid_argument("App name cannot be empty");
        }

#ifdef CFGPARSER_PLATFORM_WINDOWS
        std::string base_path = expandPath("%APPDATA%");
        return base_path + "\\" + app_name;
#elif defined(CFGPARSER_PLATFORM_MACOS)
        std::string base_path = expandPath("~/Library/Preferences");
        return base_path + "/" + app_name;
#else
        std::string base_path = expandPath("~/.config");
        return base_path + "/" + app_name;
#endif
    }

    // 获取系统默认数据目录路径
    std::string get_default_data_path(const std::string &app_name)
    {
        if (app_name.empty())
        {
            throw std::invalid_argument("App name cannot be empty");
        }

#ifdef CFGPARSER_PLATFORM_WINDOWS
        std::string base_path = expandPath("%LOCALAPPDATA%");
        return base_path + "\\" + app_name;
#elif defined(CFGPARSER_PLATFORM_MACOS)
        std::string base_path = expandPath("~/Library/Application Support");
        return base_path + "/" + app_name;
#else
        std::string base_path = expandPath("~/.local/share");
        return base_path + "/" + app_name;
#endif
    }

    // 获取系统默认日志目录路径
    std::string get_default_log_path(const std::string &app_name)
    {
        if (app_name.empty())
        {
            throw std::invalid_argument("App name cannot be empty");
        }

#ifdef CFGPARSER_PLATFORM_WINDOWS
        std::string base_path = expandPath("%LOCALAPPDATA%");
        return base_path + "\\" + app_name + "\\Logs";
#elif defined(CFGPARSER_PLATFORM_MACOS)
        std::string base_path = expandPath("~/Library/Logs");
        return base_path + "/" + app_name;
#else
        std::string base_path = expandPath("~/.local/share");
        return base_path + "/" + app_name + "/logs";
#endif
    }

    // 创建目录
    bool create_directory(const std::string &path)
    {
        if (path.empty())
        {
            return false;
        }

        try
        {
            std::filesystem::create_directories(path);
            return true;
        }
        catch (const std::exception &)
        {
            return false;
        }
    }

    const std::string get_app_name()
    {
        char path[1024];
#ifdef CFGPARSER_PLATFORM_WINDOWS
        if (GetModuleFileNameA(NULL, path, sizeof(path)))
        {
            std::string fullPath(path);
            return fullPath.substr(fullPath.find_last_of("/\\") + 1);
        }
#elif defined(CFGPARSER_PLATFORM_MACOS)
        uint32_t size = sizeof(path);
        if (_NSGetExecutablePath(path, &size) == 0)
        {
            std::string fullPath(path);
            return fullPath.substr(fullPath.find_last_of("/\\") + 1);
        }
#else
        ssize_t count = readlink("/proc/self/exe", path, sizeof(path));
        if (count != -1)
        {
            std::string fullPath(path, count);
            return fullPath.substr(fullPath.find_last_of("/\\") + 1);
        }
#endif
        return "";
    }

    [[maybe_unused]] const std::string get_executable_path()
    {
#ifdef CFGPARSER_PLATFORM_WINDOWS
        std::vector<char> buffer(MAX_PATH);
        while (true)
        {
            DWORD length = GetModuleFileNameA(nullptr, buffer.data(), static_cast<DWORD>(buffer.size()));
            if (length == 0)
            {
                return {};
            }
            if (length < buffer.size())
            {
                std::filesystem::path exe_path(buffer.data());
                exe_path.make_preferred();
                return exe_path.string();
            }
            buffer.resize(buffer.size() * 2);
        }
#elif defined(CFGPARSER_PLATFORM_MACOS)
        uint32_t size = 0;
        if (_NSGetExecutablePath(nullptr, &size) == 0)
        {
            // size already correct, fallthrough to allocation below
        }
        std::vector<char> buffer(size ? size : PATH_MAX);
        if (_NSGetExecutablePath(buffer.data(), &size) != 0)
        {
            return {};
        }
        buffer.resize(std::strlen(buffer.data()));
        char resolved[PATH_MAX];
        if (realpath(buffer.data(), resolved) != nullptr)
        {
            return std::string(resolved);
        }
        return std::string(buffer.data());
#else
        char result[PATH_MAX];
        ssize_t count = readlink("/proc/self/exe", result, sizeof(result));
        if (count != -1)
        {
            return std::string(result, static_cast<std::size_t>(count));
        }
        return {};
#endif
    }

    [[maybe_unused]] const std::string get_executable_directory()
    {
        std::string executable_path = get_executable_path();
        if (executable_path.empty())
        {
            return {};
        }
        std::filesystem::path dir_path(executable_path);
        return dir_path.parent_path().string();
    }

} // namespace cfgparser